package com.atelier.plugin.projectWizard;

import com.atelier.plugin.projectWizard.data.DataSetting;
import com.atelier.plugin.projectWizard.data.ProjectConfig;
import com.atelier.plugin.projectWizard.ui.ProjectSetting;
import com.atelier.plugin.projectWizard.util.FileContentReplacer;
import com.atelier.plugin.projectWizard.util.ICONS;
import com.atelier.plugin.projectWizard.util.MavenArchetypeGenerator;
import com.atelier.plugin.service.impl.SettingsStorageServiceImpl;
import com.intellij.ide.projectWizard.ProjectSettingsStep;
import com.intellij.ide.util.frameworkSupport.FrameworkRole;
import com.intellij.ide.util.projectWizard.*;
import com.intellij.ide.wizard.AbstractWizard;
import com.intellij.notification.*;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.module.*;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ProjectManager;
import com.intellij.openapi.projectRoots.Sdk;
import com.intellij.openapi.projectRoots.SdkTypeId;
import com.intellij.openapi.roots.ModifiableRootModel;
import com.intellij.openapi.roots.ui.configuration.ModulesProvider;
import com.intellij.openapi.startup.StartupManager;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.InvalidDataException;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.DisposeAwareRunnable;
import com.intellij.util.ScrambledOutputStream;
import org.jdom.JDOMException;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;


import javax.swing.*;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * @author tangrufei
 * @date 2023-05-12 11:01
 */
public class HywayModuleBuilder extends ModuleBuilder {
    public static int count;
    private ProjectSetting projectSetting;
    /**
     * @return
     */
    @Override
    public Icon getNodeIcon() {
        return ICONS.HwayLogo;
    }

    @Override
    public ModuleType<?> getModuleType() {
        //return new HywayModuleType();
       // return HywayModuleType.getInstance();
        return HywayModuleType.getInstance();
    }

    @Override
    public String getName() {
        return "Hyway";
    }

    @Override
    public @Nls(capitalization = Nls.Capitalization.Title) String getPresentableName() {return "Hyway";}

    @Override
    public @Nullable
    @NonNls String getBuilderId() {return getClass().getName();}

    @Override
    public @Nullable ModuleWizardStep getCustomOptionsStep(WizardContext context, Disposable parentDisposable) {
         String projectFileDirectory = context.getProjectFileDirectory();
        System.out.println("ProjectFileDirectory:  " + projectFileDirectory);
         projectSetting = new ProjectSetting(projectFileDirectory);

         HywayModuleConfigStep hywayModuleConfigStep = new HywayModuleConfigStep(projectSetting);
        Disposer.register(parentDisposable, hywayModuleConfigStep);
        return hywayModuleConfigStep;
    }


    @Override
    public @Nullable ModuleWizardStep modifySettingsStep(@NotNull SettingsStep settingsStep) {
        System.out.println("modifySettingsStep执行...");
        ModuleNameLocationSettings moduleNameLocationSettings = settingsStep.getModuleNameLocationSettings();

        String artifactId = DataSetting.getInstance().getState().getArtifactId();
        if (null != moduleNameLocationSettings && !StringUtil.isEmptyOrSpaces(artifactId)) {
            moduleNameLocationSettings.setModuleName(artifactId);
        }
        System.out.println("modifySettingsStep==BaseDir"+DataSetting.getInstance().getState().getProjectBaseDir());
        moduleNameLocationSettings.setModuleContentRoot(DataSetting.getInstance().getState().getProjectBaseDir()+"/"+DataSetting.getInstance().getState().getName());
        return super.modifySettingsStep(settingsStep);
    }

    @Override
    public @Nullable List<Module> commit(@NotNull Project project, ModifiableModuleModel model, ModulesProvider modulesProvider) {
        System.out.println("commit");
        return super.commit(project, model, modulesProvider);
    }

    @Override
    public boolean isTemplate() {
        return true;
    }

    @Override
    protected void setupModule(Module module) throws ConfigurationException {
        System.out.println("setupModule执行...");
        //super.setupModule(module);

        Project project = module.getProject();

        ProjectConfig state = DataSetting.getInstance().getState();
        Runnable r = () -> WriteCommandAction.writeCommandAction(project).run(() -> {
             String projectFilePath = module.getProject().getProjectFilePath();
            System.out.println(projectFilePath);

        });
        if (ApplicationManager.getApplication().isUnitTestMode()
                || ApplicationManager.getApplication().isHeadlessEnvironment()) {
            r.run();
            return;
        }

        if (!project.isInitialized()) {
            StartupManager.getInstance(project).registerStartupActivity(DisposeAwareRunnable.create(r, project));
            return;
        }else{
            System.out.println("已初始化");
            //FileUtil.delete(new File(module.getModuleFilePath()));
            //FileUtil.delete(new File(new File(module.getModuleFilePath()).getParent(),".idea"));
        }

        if (DumbService.isDumbAware(r)) {
            System.out.println("isDumbAware");
            r.run();
        } else {
            System.out.println("notDumbAware");
           DumbService.getInstance(project).runWhenSmart(DisposeAwareRunnable.create(r, project));
        }
    }

    /**
     * @param currentProject
     * @param project
     * @return
     */
    @Override
    public boolean validate(@Nullable Project currentProject, @NotNull Project project)
    {
             Boolean b = projectSetting.validateFields();
            System.out.println("canCreateModule");
            System.out.println(b);
            return false;
       // return super.validate(currentProject, project);
    }

    /**
     * @param project
     * @return
     */
    @Override
    public List<Module> commit(@NotNull Project project)
    {
        return super.commit(project);
    }

    @Override
    public @Nullable Project createProject(String name, String path) {
        ProjectConfig state = DataSetting.getInstance().getState();
         Project project;
        try {
            createProject(state.getProjectBaseDir());
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        Sdk moduleJdk = getModuleJdk();
        System.out.println("createProject");
        System.out.println(moduleJdk);
        File file = new File(state.getProjectBaseDir());
        System.out.println(file.getPath());
        try {
            project = ProjectManager.getInstance().loadAndOpenProject(file.getPath());
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (JDOMException e) {
            throw new RuntimeException(e);
        }
        // 手动加载 Maven 项目
        return project;
    }

    @Override
    public ModuleWizardStep modifyProjectTypeStep(@NotNull SettingsStep settingsStep) {
        System.out.println("modifyProjectTypeStep");
 ProjectWizardStepFactory.getInstance().createJavaSettingsStep(settingsStep, this, this::isSuitableSdkType);
        return null;
    }

    @Override
    public boolean isOpenProjectSettingsAfter() {
        System.out.println("isOpenProjectSettingsAfter");
        NotificationGroup notificationGroup = new NotificationGroup("notificationGroup", NotificationDisplayType.BALLOON, true);
        Notification notification = notificationGroup.createNotification("项目骨架生成成功!!,正在加载依赖中...", NotificationType.INFORMATION);
        Notifications.Bus.notify(notification);
        return super.isOpenProjectSettingsAfter();
    }

    @Override
    public @NotNull FrameworkRole getDefaultAcceptableRole() {
        return super.getDefaultAcceptableRole();
    }

    @Override
    public boolean isSuitableSdkType(SdkTypeId sdkType) {
        return super.isSuitableSdkType(sdkType);
    }


    @Override
    public ModuleWizardStep modifyStep(SettingsStep settingsStep) {
        System.out.println("modifyStep");
        return super.modifyStep(settingsStep);
    }

    public static void createProject(String path) throws IOException {
        System.out.println("createProject"+"/  "+path);
        ProjectConfig state = DataSetting.getInstance().getState();
        File file = new File(path);
        String parent = file.getParent();
        String mavenPath = HywayApplication.wrapperDir+"\\bin\\mvn";
        String mavenRepoUrl = HywayApplication.repositoryDir;
        System.out.println("parent   :"+parent);
        System.out.println("mavenPath  "+mavenPath);
        System.out.println("mavenRepoUrl  "+mavenRepoUrl);
        if (MavenArchetypeGenerator.generateMavenArchetype(parent, state.getGroup(), state.getArtifactId(), state.getVersion(), state.getPackageName(), mavenRepoUrl,mavenPath)) {
            System.out.println("骨架生成成功!!");

            FileContentReplacer.replaceStringInFile(path+"/.idea/workspace.xml","C:\\Users\\ADMINI~1\\AppData\\Local\\Temp",HywayApplication.tmp);
        } else {
            System.out.println("生成失败!!");
        }
    }
    @Override
    public void setupRootModel(@NotNull ModifiableRootModel model) throws ConfigurationException {
        System.out.println("setupRootModel执行...");
        // 设置 JDK

        if (null != this.myJdk) {
            model.setSdk(this.myJdk);
        } else {
            model.inheritSdk();
        }
        System.out.println(Objects.requireNonNull(getContentEntryPath()));
        // 生成工程路径
        String path = FileUtil.toSystemIndependentName(Objects.requireNonNull(getContentEntryPath()));
        new File(path).mkdirs();
        VirtualFile virtualFile = LocalFileSystem.getInstance().refreshAndFindFileByPath(path);
        model.addContentEntry(virtualFile);
    }

    @Override
    public @NotNull Module createModule(@NotNull ModifiableModuleModel moduleModel) throws InvalidDataException, IOException, ModuleWithNameAlreadyExists, JDOMException, ConfigurationException {
        return super.createModule(moduleModel);
    }

    @Override
    public Module createAndCommitIfNeeded(@NotNull Project project, @Nullable ModifiableModuleModel model, boolean runFromProjectWizard)
            throws InvalidDataException, ConfigurationException, IOException, JDOMException, ModuleWithNameAlreadyExists {
        final ModifiableModuleModel moduleModel = model != null ? model : ModuleManager.getInstance(project).getModifiableModel();
        final Module module = createModule(moduleModel);
        return module;
    }

    @Override
    public @Nullable Module commitModule(@NotNull Project project, @Nullable ModifiableModuleModel model) {
        return super.commitModule(project, model);
    }

    /**
     * @param wizardContext
     * @param modulesProvider
     * @return
     */
    @Override
    public ModuleWizardStep[] createWizardSteps(@NotNull WizardContext wizardContext, @NotNull ModulesProvider modulesProvider)
    {
        return new ModuleWizardStep[]{};
    }


    /**
     * @return
     */
    @Override
    public @NotNull List<Class<? extends ModuleWizardStep>> getIgnoredSteps()
    {
        List<Class<? extends ModuleWizardStep>> ignoredSteps = new ArrayList<>();
        ignoredSteps.add(ProjectSettingsStep.class);
        return ignoredSteps;
    }

    /**
     * @return
     */
    //@Override
    //public boolean canCreateModule()
    //{
    //     Boolean b = projectSetting.validateFields();
    //    System.out.println("canCreateModule");
    //    System.out.println(b);
    //    return false;
    //}
}
